package com.oanda.blackberry.net;

import java.io.IOException;
import java.io.InterruptedIOException;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.HttpsConnection;

import net.rim.device.api.servicebook.ServiceBook;
import net.rim.device.api.servicebook.ServiceRecord;
import net.rim.device.api.system.CoverageInfo;
import net.rim.device.api.system.CoverageStatusListener;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.system.WLANConnectionListener;
import net.rim.device.api.system.WLANInfo;

import com.oanda.blackberry.util.AbstractViewPanel;
import com.oanda.blackberry.util.Model;
import com.oanda.blackberry.util.PropertyChangeEvent;
import com.oanda.blackberry.util.log.Logger;

public class AutoConnectionManager implements CoverageStatusListener, WLANConnectionListener,
        AbstractViewPanel {
    public static final int NB_OF_TRIES = 6;
    public static final String CONNECTION_TIMEOUT = ";ConnectionTimeout=";
    private static final int TIMEOUT = 20000;
    public static final int CONNECTION_AUTOMATIC = 0;
    public static final int CONNECTION_BIS_B = 1;
    public static final int CONNECTION_WAP = 2;
    public static final int CONNECTION_DIRECT_TCP = 3;
    public static final int CONNECTION_MDS = 4;
    public static final int CONNECTION_WAP10 = 5;
    public static String connectionSuffix;
    private static AutoConnectionManager instance;

    public AutoConnectionManager() {
        update();
    }

    public static AutoConnectionManager getInstance() {
        if (instance == null) {
            instance = new AutoConnectionManager();
        }
        return instance;
    }

    public static void update() {
        connectionSuffix = getConnectionSuffix(Model.getModel().getConnectionSuffixIndex());
    }

    public static void update(int index) {
        connectionSuffix = getConnectionSuffix(index);
    }

    public void coverageStatusChanged(int newCoverage) {
        update();
    }

    public void networkConnected() {
        update();
    }

    public void networkDisconnected(int reason) {
        update();
    }

    private static String getUID() {
        String uid = null;
        ServiceBook sb = ServiceBook.getSB();
        ServiceRecord[] records = sb.findRecordsByCid("WPTCP");
        for (int i = 0; i < records.length; i++) {
            if ((!records[i].isValid()) || (records[i].isDisabled())
                    || (records[i].getUid() == null) || (records[i].getUid().length() == 0))
                continue;
            if ((records[i].getUid().toLowerCase().indexOf("wptcp") == -1)
                    || (records[i].getUid().toLowerCase().indexOf("wifi") != -1)
                    || (records[i].getUid().toLowerCase().indexOf("mms") != -1)) {
                continue;
            }

            uid = records[i].getUid();
            break;
        }

        return uid;
    }

    public static String getConnectionSuffix(int connectionType) {
        if ((WLANInfo.getWLANState() == 4620) && (RadioInfo.areWAFsSupported(4))) {
            return ";interface=wifi";
        }
        try {
            switch (connectionType) {
            case 0:

                if (CoverageInfo.isCoverageSufficient(1)) {
                    String uid = getUID();
                    if (uid != null) {
                        return ";ConnectionUID=" + uid;
                    }
                }

                if (CoverageInfo.isCoverageSufficient(4)) {
                    return ";deviceside=false;ConnectionType=mds-public";
                }

                if (CoverageInfo.isCoverageSufficient(2)) {
                    return ";deviceside=false";
                }

                return ";deviceside=true";
            case 1:

                return ";deviceside=false;ConnectionType=mds-public";
            case 2:

                return ";ConnectionUID=" + getUID();
            case 3:

                return ";deviceside=true";
            case 4:

                return ";deviceside=false";

            }
            return "";
        } catch (Exception e) {
        }
        return "";
    }

    public static HttpsConnection request(String url) throws Exception {
        HttpsConnection con = null;
        try {
            String fullURL = url + ";ConnectionTimeout=20000" + connectionSuffix;

            Logger.log(fullURL);
            int tries = 0;
            while (tries < 6) {
                try {
                    if (con != null) {
                        con.close();
                    }
                    con = (HttpsConnection) Connector.open(fullURL, 3);

                    if (con == null) {
                        tries++;
                        continue;
                    }

                } catch (InterruptedIOException e) {
                } catch (IOException e) {
                    tries++;
                }
            }
            return con;
        } catch (Exception e) {
            throw e;
        }

    }

    public static HttpConnection requestNonSecure(String url) throws Exception {
        HttpConnection con = null;
        try {
            String fullURL = url + ";ConnectionTimeout=20000" + connectionSuffix;

            Logger.log(fullURL);
            int tries = 0;
            while (tries < 6) {
                try {
                    if (con != null) {
                        con.close();
                    }
                    con = (HttpConnection) Connector.open(fullURL, 3);

                    if (con == null) {
                        tries++;
                        continue;
                    }
                } catch (InterruptedIOException e) {
                } catch (IOException e) {
                    tries++;
                }
            }
            return con;
        } catch (Exception e) {
            throw e;
        }

    }

    public void modelPropertyChange(PropertyChangeEvent evt) {
        if ((evt != null) && (evt.getPropertyName().equals("setConnectionSuffixIndex"))
                && (evt.getNewValue() != null) && ((evt.getNewValue() instanceof Integer)))
            update(((Integer) evt.getNewValue()).intValue());
    }
}
